闲话 22.10.19

闲话

听说写一些比较意识流的闲话会像闲话一点(
比方说多头

但是既然都开始写了那就无所谓像了
想啥就写啥吧

话说jjdw打字的手法实在是娴熟
每次看到都想吐槽来着
我还得多练(

话说回来
打KTT的时候一直又WA又T不知道为什么
然后贺了一个加号
然后A了
我不知道为什么

[今天要推的歌是Aster!]
话说下午我在哼安河桥
然后crs吐槽歌十分悲伤
然后我唱Aster 然后问crs为什么不吐槽了
然后crs表示歌很好听

我不是十分的理解

杂题

关于下面的一些讨论,EI 通过了四种方式证明了某个更强的结论

P4389 付公主的背包

付公主有一个可爱的背包qwq

这个背包最多可以装 105 大小的东西

付公主有 n 种商品,她要准备出摊了

每种商品体积为 vi,都有无限件

给定 m,对于 s[1,m],请你回答用这些商品恰好装 s 体积的方案数

n,m105,vim

板子题。

首先这题用普通完全背包肯定是跑不动的。于是考虑一个多项式优化。

对于一个商品,我们可以把它拆成选 k (k>=0) 种的可能性加和。
考察单项式相乘的情况:

axi×bxj=abxi+j

可以看到,假设我们将可能性看做单项式的系数,背包容量看做单项式的指数,则两个单项式相乘就可以看做背包决策空间内两种决策的合并。推广到多项式,不难得到第 k 种商品的表示法:

fk(x)=i0xvk×i=11xvk

第二个等号考虑 fk(x)×xvk+1=fk(x)

于是我们只需要把所有多项式卷积起来,取答案的前 m 项系数就是答案。
但是如果直接卷复杂度就是 O(n2logn) 的了。然后考虑优化。

G(x) 为答案的生成函数。立得

G(x)=i=1nfi(x)=1i=1n(1xvi)

我们只需要求出分母,求个逆就是答案。
然后考虑分母:

i=1n(1xvi)=expln(i=1n(1xvi))=expi=1nln(1xvi)=expi=1nj1xvijj=expj11ji=1nxvij=expj11jjkmxjki=1n[vi=k]

第三步考虑一个 ln(1xk) 的麦克劳林展开。
随后我们就可以通过用一个桶预处理第三个求和号,用 O(i=1mmi)=O(mlogm) 的时间得到需要的前 (m+1) 项。

得到所有系数后做一次 exp 做一次求逆即可得到答案。

code
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define rep(i, a, b) for (register int(i) = (a), i##_ = (b) + 1; (i) < i##_; ++(i))
#define pre(i, a, b) for (register int(i) = (a), i##_ = (b) - 1; (i) > i##_; --(i))
using namespace std;

const int N = 3e5 + 10, mod = 998244353, g = 3;
const int siz_int = sizeof(int);

#ifdef ONLINE_JUDGE
    char buf[1<<21], *p1 = buf, *p2 = buf;  inline char getc() { return (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<21, stdin), p1 == p2) ? EOF : *p1++); }
    #define getchar getc
#endif
template <typename T> inline void get(T & x){
	x = 0; char ch = getchar(); bool f = false; while (ch < '0' or ch > '9') f = f or ch == '-',  ch = getchar();
	while (ch >= '0' and ch <= '9') x = (x<<1) + (x<<3) + (ch^48), ch = getchar(); f && (x = -x);
} template <typename T, typename ... Args> inline void get(T & x, Args & ... _Args) { get(x); get(_Args...); }

int n, m, len = 1, a[N], cnt[N], ifv[N];

typedef long long ll; typedef __int128 lll;
struct FastMod { int m; ll b; FastMod(int _m) { m = _m; b = ((lll)1<<64) / m; } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod(mod);
int add(int a, int b) { return (a += b) >= mod ? a - mod : a; } template <typename ...Args> int add(int a, Args ...b) { return add(a, add(b...)); }
int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }

int btrs[N << 1];
inline int initrs(int k) {
    int limit = 1;
    while (limit < k) limit <<= 1;
    for (register int i = 0 ; i < limit; i ++) btrs[i] = (btrs[i >> 1] >> 1) | ((i & 1) ? limit >> 1 : 0);
    return limit;
}

inline int qp(int a, int b) {
    int ret = 1;
    while (b) {
        if (b & 1) ret = mul(ret, a);
        a = mul(a, a);
        b >>= 1;
    } return ret;
} inline int inv(int a) { return qp(a, mod-2); }
const int invg = inv(g), inv2 = (mod + 1) >> 1;

const int L = 1 << 21;
int w[2][L];
int IUR() {
    w[0][0] = w[1][0] = 1; int wn = qp(g, (mod-1) / L);
    for (register int i = 1; i < L; i++) w[0][L - i] = w[1][i] = mul(w[1][i - 1], wn);
    return 1;
} int dummy = IUR();

struct poly {
    vector <int> f; 
    int operator [] (const int & pos) const { return f[pos]; }
    int & operator [] (const int & pos) { return f[pos]; }
    int deg() {return f.size(); }
    int deg() const  {return f.size(); }
    void Set(int n) { f.resize(n); }
    void Adjust() { while (f.size() > 1 and f.back() == 0) f.pop_back(); }
    void Reverse() { reverse(f.begin(), f.end()); }
    void scan(int n = -1) { if (n < 0) get(n); Set(n); for (register int i = 0; i < n; i++) get(f[i]); }
    void print() { for (int x : f) printf("%d ", x); }
	void getFac(int k) { Set(k); f[0] = 1; for (int i = 1; i <= k; i++) f[i] = mul(f[i - 1], i); }
	void getInv(int k) { Set(k); f[0] = f[1] = 1; for (int i = 1; i <= k; ++ i) f[i] = mul(mod - mod / i, f[mod % i]); }
    void deri() { for (register int i = 0; i + 1 < (int)f.size(); ++i) f[i] = mul(f[i+1], i+1); f.back() = 0; }
    void intg() { for (register int i = f.size() - 1; i >= 1; --i) f[i] = mul(f[i-1], inv(i)); f[0] = 0; }
    poly Deri() { 
        poly ret; ret.Set(deg());
        for (int i = 0; i + 1 < deg(); ++i) {
            ret[i] = mul(f[i+1], i+1);
        } return ret;
    } poly Intg() {
        poly ret, inv; ret.Set(deg()), inv.getInv(deg() - 1);
        for (int i = deg() - 1; i >= 1; --i) {
            ret[i] = mul(f[i-1], inv[i]);
        } return ret;
    }
    inline void NTT (const int lim, const int type) {
        Set(lim); 
        for (register int i = 0; i < lim; i++) if (i < btrs[i]) swap(f[i], f[btrs[i]]);
        for (register int mid = 1, x, y; mid < lim; mid <<= 1) {
            for (register int i = L / (mid<<1), j = 0; j < lim; j += (mid << 1)) {
                for (register int k = 0; k < mid; k++) {
                    x = f[j + k], y = mul(w[type][i * k], f[j + k + mid]);
                    f[j + k] = add(x, y);
                    f[j + k + mid] = add(x, mod - y);
                }
            }
        } if (type == 1) return;
        int inv = qp(lim, mod - 2);
        for (register int i = 0; i < lim; i++) f[i] = mul(f[i], inv);
    } 
    friend poly operator + (const poly & x, const poly & y) {
        poly ret; ret.Set(max(x.deg(), y.deg()));
        for (register int i = 0; i < x.deg(); ++i) ret[i] = x[i];
        for (register int i = 0; i < y.deg(); ++i) ret[i] = add(ret[i], y[i]);
        return ret;
    } void operator += (const poly & x) {
        Set(max(deg(), x.deg()));
        for (register int i = 0; i < x.deg(); ++i) f[i] = add(f[i], x[i]);
    } 
    friend poly operator - (const poly & x, const poly & y) {
        poly ret; ret.Set(max(x.deg(), y.deg()));
        for (register int i = 0; i < x.deg(); ++i) ret[i] = x[i];
        for (register int i = 0; i < y.deg(); ++i) ret[i] = add(ret[i], mod - y[i]);
        return ret;
    } void operator -= (const poly & x) {
        Set(max(deg(), x.deg()));
        for (register int i = 0; i < x.deg(); ++i) f[i] = add(f[i], mod - x[i]);
    } 
    friend poly operator * (const poly & x, const poly & y) {
        poly ret, A = x, B = y;
        int limit = initrs(A.deg() + B.deg() - 1);
        A.NTT(limit, 1), B.NTT(limit, 1); ret.Set(limit);
        for (register int i = 0; i < limit; i++) ret[i] = mul(A[i], B[i]);
        ret.NTT(limit, 0); ret.Adjust();
        return ret;
    } void operator *= (const poly & x) {
        poly A = x;
        int limit = initrs(deg() + A.deg() - 1);
        A.NTT(limit, 1); NTT(limit, 1);
        for (register int i = 0; i < limit; i++) f[i] = mul(A[i], f[i]);
        NTT(limit, 0); Adjust();
    }
    poly Inv() {
        poly ret; ret.Set(1);
        if (f.empty()) return ret;
        ret[0] = inv(f[0]); poly A, B;
        for (register int len = 2, limit; len < (deg() << 1); len <<= 1) {
            A.f.assign((*this).f.begin(), (*this).f.begin() + min(len, deg()));
            B = ret; B.Set(min(len, deg()));
            limit = initrs(A.deg() + B.deg() - 1);
            A.NTT(limit, 1); B.NTT(limit, 1);
            ret.Set(limit);
            for (register int i = 0; i < limit; i++) ret[i] = mul(add(2, mod - mul(A[i], B[i])), B[i]);
            ret.NTT(limit, 0);
            ret.Set(len);
        } ret.Set(deg()); return ret;
    }
    poly Ln() {
        poly ret = Deri(), Iv = Inv();
        ret *= Iv; ret.intg(); ret.Set(deg());
        return ret;
    } 
    poly Exp() {
        poly ret; ret.Set(1); ret[0] = 1;
        poly A, B;
        for (register int len = 2; len < (deg() << 1); len <<= 1) {
            ret.Set(len); A = ret.Ln();
            B.f.assign((*this).f.begin(), (*this).f.begin() + min(len, deg()));
            B -= A; B[0]++; ret *= B;
            ret.Set(len);
        } ret.Set(deg()); return ret;
    }
} F;

signed main() {
    get(n, m);
    rep(i,1,n) get(a[i]), cnt[a[i]]++;
    while (len <= m) len <<= 1;
    ifv[0] = ifv[1] = 1;
    rep(i,2,len) ifv[i] = mul((mod - mod / i), ifv[mod % i]);
    F.Set(len); 
    rep(i,1,m) if (cnt[i]) {
        for (int j = 1; i * j < len; ++ j) {
            F[i * j] = add(F[i * j], mul(cnt[i], (mod - ifv[j])));
        }
    }
    F = F.Exp();
    F = F.Inv();
    rep(i,1,m) printf("%d\n", F[i]);
}



actually还做了一道题 P5175
但是太水了略去

但是想请各位卡卡常(



[能不能再给力一点啊?]

P7435 简单的排列计数

题面比较形式化,在此不放。

多项式题。

由经典dp结论,我们有 答案即为

[xk]i=1n1(ix)i1ix

i=1n1(ix)i1ix=exp(i=1nln(1(ix)i)ln(1ix))

讨论减号前后的两个部分。

首先是前面的:

i=1nln(1(ix)i)=i=1nj1(ix)ijj=j11jijniij×xij

n,k 其实是同阶的。直接算就完了。

然后是后面的:

i=1nln(1ix)=i=1nj1(ix)jj=j1xjji=1nij=j1xjj(1j+1i1j(j+1i)Bi(n+1)ji+1)j=j1xjj(j+1)i1j(j+1i)Bi(n+1)ji+1

Bi 是伯努利数。对多项式大佬来说显然不是什么问题
Bi 的EGF是 xex1

于是我们就能得到答案了。

懒得写码了(

posted @   joke3579  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示